%token ERROR NONE EOI TAB_INC TAB_DEC NEW_LINE WHITESPACE COMMENT ID VAL_INT VAL_STR IF ELIF ELSE WHILE FOR IN DEF TRUE FALSE AND OR NOT EQUAL NOT_EQUAL LESS MORE LESS_E MORE_E PASS RETURN PRINT COLON ASSIGN PLUS MINUS MULT DIV BR_L BR_R BR_Q_L BR_Q_R COMMA ASSIGN_PLUS ASSIGN_MINUS ASSIGN_MULT ASSIGN_DIV

%%

program:
    start EOI
    {
        printf("True.\n");
        exit(0);
    }
;

start:
    expr start__
    |
    /* empty */
;

start__:
    expr start__
    |
    /* empty */
;

expr:
    assign_expr new_line_rule |
    if_expr |
    while_expr |
    for_expr |
    print_expr new_line_rule |
    PASS new_line_rule |
    ve new_line_rule |
    new_line_rule
;

new_line_rule:
    COMMENT NEW_LINE
    |
    NEW_LINE
;





/* COMPLEX EXPRESSIONS */

assign_expr:
    ve_index oper_assign ve
;

if_expr:
    IF ve COLON new_line_rule TAB_INC start TAB_DEC else_expr
;
else_expr:
    ELSE COLON new_line_rule TAB_INC start TAB_DEC
    |
    /* empty */
;

while_expr:
    WHILE ve COLON new_line_rule TAB_INC start TAB_DEC
;

for_expr:
    FOR ID IN ve COLON new_line_rule TAB_INC start TAB_DEC
;

print_expr:
    PRINT ve_list_print
;





/* VALUABLE EXPRESSION */

ve_list:
    ve ve_list__
    |
    /* empty */
;
ve_list__:
    COMMA ve ve_list__
    |
    /* empty */
;

ve_list_print:
    ve ve_list_print__
    |
    /* empty */
;
ve_list_print__:
    COMMA ve_list_print____
    |
    /* empty */
;
ve_list_print____:
    ve COMMA ve_list_print____
    |
    /* empty */
;


ve:
    ve_or
;


ve_or:
/* x or y */
    ve_or ve_or__
    |
    ve_and
;
ve_or__:
    OR ve_and
;


ve_and:
/* x and y */
    ve_and ve_and__
    |
    ve_not
;
ve_and__:
    AND ve_not
;


ve_not:
/* not x */
    NOT ve_not
    |
    ve_compare
;


ve_compare:
/* x == y, x > y, x >= y etc. */
    ve_compare ve_compare__
    |
    ve_plus_minus
;
ve_compare__:
    oper_compare ve_plus_minus
;


ve_plus_minus:
/* x + y, x - y */
    ve_plus_minus ve_plus_minus__
    |
    ve_mult_div
;
ve_plus_minus__:
    oper_plus_minus ve_mult_div
;


ve_mult_div:
/* x * y, x // y */
    ve_mult_div ve_mult_div__
    |
    ve_unary_plus_minus
;
ve_mult_div__:
    oper_mult_div ve_unary_plus_minus
;


ve_unary_plus_minus:
/* -x, +x */
    MINUS ve_index
    |
    PLUS ve_index
    |
    ve_index
;


ve_index:
/* x[y] */
    ve_brackets ve_index__
;
ve_index__:
    BR_Q_L ve BR_Q_R
    |
    /* empty */
;


ve_brackets:
/* (x) */
    BR_L ve BR_R
    |
    ve_array
;


ve_array:
/* [x] */
    BR_Q_L ve_list BR_Q_R
    |
    ve_funcall_id_or_value
;


ve_funcall_id_or_value:
    ID ve_funcall_id_or_value__ | value
;
ve_funcall_id_or_value__:
    BR_L funcall_arguments BR_R
    |
    /* empty */
;

funcall_arguments:
    ve_list
;


value:
    TRUE | FALSE | VAL_INT | VAL_STR
;





/* OPERATORS */

oper_assign:
    ASSIGN | ASSIGN_PLUS | ASSIGN_MINUS | ASSIGN_MULT | ASSIGN_DIV
;

oper_plus_minus:
    PLUS | MINUS
;

oper_mult_div:
    MULT | DIV
;

oper_compare:
    EQUAL | NOT_EQUAL | MORE | LESS | MORE_E | LESS_E
;